package com.nulldev.util.manage.legacy;

import java.text.DecimalFormat;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.atomic.LongAdder;

import com.nulldev.util.concurrency.threadIt.v4.emapi.ExecutorManager;
import com.nulldev.util.logging.Logger;
import com.nulldev.util.logging.LoggerFactory;

public class Timer implements Runnable {
	protected final AtomicReference<Long> UPDATE_RATE = new AtomicReference<Long>(5L);
	private final LongAdder TICK = new LongAdder();
	private final AtomicBoolean paused = new AtomicBoolean();
	private final AtomicBoolean stop = new AtomicBoolean();

	private final static Logger log = LoggerFactory.getLogger();

	public Timer() {
	}

	public Timer(final long updateRate) {
		this.UPDATE_RATE.lazySet(updateRate);
	}

	public void start() {
		ExecutorManager.get().queueTask(this);
	}

	public void start(final ExecutorService serv) {
		serv.execute(this);
	}

	@Override
	public void run() {
		while (true) {
			if (this.stop.get()) {
				break;
			}
			final long UPDATE_RATE = this.UPDATE_RATE.get();
			if (!this.paused.get()) {
				if (this.TICK.sum() + 1 > Long.MAX_VALUE) {
					this.TICK.reset();
					log.error("Timer on thread '" + "nullUtil: Timer" + "' has reached max value. It has been set to the minimal value to prevent overflow.");
				}
				this.TICK.add(UPDATE_RATE);
				updateF();
				try {
					Thread.sleep(UPDATE_RATE);
				} catch (InterruptedException e) {
					Thread.interrupted();
				}
			} else {
				try {
					Thread.sleep(UPDATE_RATE);
				} catch (InterruptedException e) {
					Thread.interrupted();
				}
			}
		}
	}

	void updateF() {
	}

	public long ticks() {
		return this.TICK.sum();
	}

	public String ticks2s() {
		final DecimalFormat frm = new DecimalFormat("#.#");
		return frm.format((double) this.TICK.sum() / 1000L) + "s";
	}

	public void reset() {
		this.TICK.reset();
	}

	public void update(final long newValue) {
		this.TICK.reset();
		this.TICK.add(newValue);
	}

	public void pause() {
		this.paused.lazySet(true);
	}

	public void unpause() {
		this.paused.lazySet(false);
	}

	public void add(final long val) {
		this.TICK.add(val);
	}

	public void setDelay(final long RATE) {
		this.UPDATE_RATE.lazySet(RATE);
	}

	public boolean isTicks(final long ticks) {
		final boolean out = (this.TICK.sum() % ticks != 0);
		return out;
	}

	public boolean hasReached(final long ticks) {
		return this.TICK.sum() >= ticks;
	}

	public void stop() {
		this.stop.lazySet(true);
	}

	public boolean running() {
		return this.stop.get();
	}
}
